#ifndef G_MATH_RAY_1234567
#define G_MATH_RAY_1234567
#include <cmath>


template<class T>
class Vec3Basic
{
public:
	Vec3Basic() : x((T)0.0), y((T)0.0), z((T)0.0) {}; //TODO: check and see how efficient this typecasting is
	Vec3Basic(T X, T Y, T Z) : x(X), y(Y), z(Z) {};
	T x, y, z;

	T dot(const Vec3Basic<T>& v) const
	{
		return x * v.x + y * v.y + z * v.z;
	}
	T length() const
	{
		return sqrt( x * x + y * y + z * z );
	}
	void normalize()
	{
		T l = 1 / length();
		x *= l;
		y *= l;
		z *= l;
	}
	Vec3Basic<T> normal() const
	{
		T l = 1 / length();
		float x1, y1, z1;
		x1 = x * l;
		y1 = y * l;
		z1 = z * l;
		return Vec3Basic<T>( x1, y1, z1 );
	}
	Vec3Basic<T> cross(const Vec3Basic<T>& v)
	{
		//return Vec3Basic<T>(y*v.z-z*v.y, -(x*v.z-z*v.x), x*v.y-y*v.x);
		return Vec3Basic<T>(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x);
	}

	friend Vec3Basic<T> operator + ( const Vec3Basic<T>& v1, const Vec3Basic<T>& v2 )
	{
		return Vec3Basic<T>( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z );
	}
	friend Vec3Basic<T> operator + ( const Vec3Basic<T>& v1, const T& f )
	{
		return Vec3Basic<T>( v1.x + f, v1.y + f, v1.z + f );
	}
	friend Vec3Basic<T> operator - ( const Vec3Basic<T>& v1, const Vec3Basic<T>& v2 )
	{
		return Vec3Basic<T>( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z );
	}
	friend Vec3Basic<T> operator - ( const Vec3Basic<T>& v1, const T& f )
	{
		return Vec3Basic<T>( v1.x - f, v1.y - f, v1.z - f );
	}
	friend Vec3Basic<T> operator / ( const Vec3Basic<T>& v1, const T& f )
	{
		return Vec3Basic<T>( v1.x / f, v1.y / f, v1.z / f );
	}
	friend Vec3Basic<T> operator * ( const Vec3Basic<T>& v, T f )
	{
		return Vec3Basic<T>( v.x * f, v.y * f, v.z * f );
	}
	friend Vec3Basic<T> operator * ( const Vec3Basic<T>& v1, Vec3Basic<T>& v2 )
	{
		return Vec3Basic<T>( v1.x * v2.x, v1.y * v2.y, v1.z * v2.z );
	}
	friend Vec3Basic<T> operator * ( T f, const Vec3Basic<T>& v )
	{
		return Vec3Basic<T>( v.x * f, v.y * f, v.z * f );
	}
	void set(const T& a, const T& b, const T& c)
	{
		x = a;
		y = b;
		z = c;
	}
};
typedef Vec3Basic<float> Vec3;
typedef Vec3Basic<int> Color3;


class Ray
{
public:
	Ray() : origin(), direction() {};
	Ray( const Vec3& origin, const Vec3& direction ) : origin( origin ), direction( direction ) {};
	Vec3 origin, direction;
};

#endif
